package com.redhat.auth.log;

import com.redhat.auth.log.common.ValueBean;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.aop.support.AopUtils;
import com.redhat.auth.log.common.LogDescriptionBean;
import com.dayatang.domain.InstanceFactory;
import com.redhat.auth.log.annotation.LogBizCall;
import com.redhat.auth.log.annotation.LogBizExecution;
import com.redhat.auth.log.annotation.OperaType;
import com.redhat.auth.log.core.LogAnalysisFailure;
import com.redhat.auth.log.core.LogAnalysisSuccess;
import com.redhat.auth.log.core.domain.BizLogInfo;
import com.redhat.auth.log.listener.LogInfoUtil;
import com.redhat.auth.log.parse.AnnotationParse;
import com.redhat.auth.log.parse.CriteriaParse;
import com.redhat.auth.log.query.LogQueryChannel;
import com.redhat.auth.log.common.CacheDataValue;

public aspect LogAspectJ {

	private static LogQueryChannel logQueryChannel;

	/**
	 * 拦截非静态方法
	 */
	public pointcut logMethod():
		call(@LogBizCall !static * *(..)) || execution(@LogBizExecution !static * *(..));
	

	Object around():logMethod(){
		Object result = null;
		LogBizCall logBizCall = null;
		LogBizExecution logBizExecution = null;
		HashMap<String, List> beforeValueMap = new HashMap<String, List>();
		HashMap<Class, List<String>> keyCriterias = new HashMap<Class, List<String>>();
		LogDescriptionBean logBean = null;
		HashMap<Integer, Object> args = null;
		CacheDataValue cacheDataValue = new CacheDataValue();
		BizLogInfo bizLogInfo = new BizLogInfo();
		try {
			MethodSignature meth = (MethodSignature) thisJoinPoint
					.getSignature();
			String methodName = meth.getName();
			Class target = null;
			boolean proxy = AopUtils.isAopProxy(thisJoinPoint.getTarget());
			if (proxy) {
				target = AopUtils.getTargetClass(thisJoinPoint.getTarget());
				Class[] interfaces = target.getInterfaces();
				for (Class interfaceClass : interfaces) {
					if (interfaceClass.getMethod(methodName,
							meth.getParameterTypes()) != null) {
						target = interfaceClass;
						break;
					}
				}
			} else {
				target = thisJoinPoint.getTarget().getClass();
			}
			Method method = target.getMethod(methodName,
					meth.getParameterTypes());
			Annotation[] thisAnnotations = method.getAnnotations();

			for (Annotation annotation : thisAnnotations) {
				if (annotation instanceof LogBizCall) {
					logBizCall = (LogBizCall) annotation;
					break;
				}
				if (annotation instanceof LogBizExecution) {
					logBizExecution = (LogBizExecution) annotation;
					break;
				}
			}
			bizLogInfo.setOperator(LogInfoUtil.getThreadLocalVariable(LogInfoUtil.SYSTEM_OPERATOR_KEY).toString());
			bizLogInfo.setServerIp(LogInfoUtil.getGlobalVariable(LogInfoUtil.SYSTEM_ADDRESS_KEY).toString());
			bizLogInfo.setSystem(LogInfoUtil.getGlobalVariable(LogInfoUtil.SYSTEM_NAME_KEY).toString());
			bizLogInfo.setClientIp(LogInfoUtil.getThreadLocalVariable(LogInfoUtil.CLIENT_ADDRESS_KEY).toString());
			
			if(logBizCall!=null)logBean = AnnotationParse.parseAnnotation(logBizCall);
			if(logBizExecution!=null)logBean = AnnotationParse.parseAnnotationExecution(logBizExecution);
			
			String[] argKeys = meth.getParameterNames();
			Object[] argValues = thisJoinPoint.getArgs();
		    args = getParamValue(argKeys, argValues);
			Collection<ValueBean> valueBeans = logBean.getValues().values();
			
			cacheDataValue.setArgs(args);
			cacheDataValue.setThisClassValue(thisJoinPoint.getTarget());
			
			for (ValueBean valueBean : valueBeans) {
				if (!valueBean.getOperaType().equals(OperaType.add)) {
					List<String> criteria = CriteriaParse.parseSQL(valueBean,cacheDataValue.initKeyValue(valueBean.getQueryKeyValues()));
					List beforeQueryValue = getLogQueryChannel().queryByCriteria(criteria);
					beforeValueMap.put(valueBean.getEntity().getSimpleName(),beforeQueryValue);
					keyCriterias.put(valueBean.getEntity(),criteria);
				}
			   cacheDataValue.setBeforeValues(beforeValueMap);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		try {
			result = proceed();
		} catch (Exception e) {
			// 发生异常
			LogAnalysisFailure log = new LogAnalysisFailure(logBean,e,bizLogInfo);
			Thread t = new Thread(log);
			t.start();
			throw new RuntimeException(e.getMessage());
		}

		try {
			// 后值的处理,托管给线程
			cacheDataValue.setResult(result);
			HashMap<String,Object> value = null;
			Collection<ValueBean> valueBeans = logBean.getValues().values();
			for (ValueBean valueBean : valueBeans) {
				if (valueBean.getOperaType().equals(OperaType.add)) {
					value = cacheDataValue.initKeyValue(valueBean.getQueryKeyValues());
					keyCriterias.put(valueBean.getEntity(), CriteriaParse.parseSQL(valueBean,value));
				}
			}
			LogAnalysisSuccess log = new LogAnalysisSuccess(logBean,keyCriterias,bizLogInfo);
			log.initValue(cacheDataValue);
			//log.initEntityValue(value);
			Thread t = new Thread(log);
			t.start();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

	private HashMap<Integer, Object> getParamValue(String[] keys,
			Object[] values) {
		HashMap params = new HashMap<String, Object>();
		for (int i = 0; i < keys.length; i++) {
			params.put(i, values[i]);
		}
		return params;
	}

	public static LogQueryChannel getLogQueryChannel() {
		if (logQueryChannel == null)
			logQueryChannel = InstanceFactory
					.getInstance(LogQueryChannel.class);
		return logQueryChannel;
	}
}